import ConfigParser
from Utilities import AddSep
import json, os

__doc__ = """\
Pygmund.Id 
	Configuration Module for Cognition Application Framework
	
description:
	Uses a JSON-based configuration file.
	
usage:
	import Cognition.Pygmund.Id as Id
	
	conf = Id.Init("/etc/cognition.conf")

example:
	conf = Id.Init("~/.config/Cognition/cognition.conf")
	if conf:
		section_conf = conf.Get("SECTION")
		if conf.Set("SECTION","OPTION","value")[0]:
			print conf.Get("SECTION","OPTION")

"""

class __CONF:
	def __init__(self):
		self.APP_CONF_DIR = "id"
		self.APP_CONF_FILE = "app.conf"
		self.DEV_CONF_DIR = "Pystalt"
		self.DEV_CONF_FILE = "cognition.conf"
		self.SYS_CONF_DIR = "/etc"
		self.SYS_CONF_FILE = "cognition.conf"
		self.CONF_FILE = ""
		self.CONF = False
	
	def Save(self):
		try:
			f = open(self.CONF_FILE, "wb")
			json.dump(self.CONF, f, indent=4)
			f.close()
			return (True, "Configuration File Saved.")
		except OSError, e:
			return (False, "Could not save configuration: %s" % e.strerror)
		except IOError, e:
			return (False, "Could not save configuration: %s" % e.strerror)
	
	def Load(self):
		try:
			if os.path.exists(self.CONF_FILE):
				f = open(self.CONF_FILE, "rb")
				self.CONF = json.load(f)
				f.close()
			else:
				f = open(self.CONF_FILE, "wb")
				json.dump({}, f, indent=4)
				f.close()
				f = open(self.CONF_FILE, "rb")
				self.CONF = json.load(f)
				f.close()
			return (True, "Configuration File Loaded.")
		except OSError, e:
			return (False, "Could not load configuration: %s" % e.strerror)
		except IOError, e:
			return (False, "Could not load configuration: %s" % e.strerror)
	
	def Set(self, section, option=0, value=0):
		"""
		Id.Set(section, option, value)
			Set configuration options, and/or create sections to a configuration.
		
		returns:
			tupple(status, msg)
				status = True/False
				msg = status message
		"""
		if section == 0:
			# No sections to configuration
			self.CONF[option] = value
		else:
			if section in self.CONF:
				if option == 0:
					# Blank Section..
					self.CONF[section] = {}
				else:
					self.CONF[section][option] = value
			else:
				# Create Section and Option
				self.CONF[section] = {}
				if not option == 0:
					self.CONF[section][option] = value
		
		# Save Configuration
		return self.Save()
	
	def Get(self, section=0, option=0):
		"""
		Id.Get
			Retrieves configuration sections/options from configuration file.
		
		returns:
			tupple(status, msg)
			status = True/False
			msg = status message
		"""
		if section == 0:
			# Get all sections, or no sections in conf
			if option == 0:
				# Return entire conf
				return self.CONF
			else:
				# Return option...
				if option in self.CONF:
					return self.CONF[option]
				else:
					return (False, "Option does not exist.")
		else:
			if section in self.CONF:
				# Get section within conf...
				if option == 0:
					# Return entire section
					return self.CONF[section]
				else:
					# Return option within section...
					if option in self.CONF[section]:
						return self.CONF[section][option]
					else:
						return (False, "Option '%s' does not exist within section %s" % (option, section))
			else:
				return (False, "Section '%s' does not exist." % section)
			
def Init(conf):
	"""
	Id.Init(conf)
	
	Initialize configuration file.
	
	conf keyword defaults:
		app = Cognition Application (relative to app, id/app.conf)
		dev = Cognition Dev Environment (relative to dev environment, Pystalt/cognition.conf)
		sys = System-wide (/etc/cognition.conf)
				
	"""
	# Set the configuration path and file
	confObj = __CONF()
	if conf == "app":
		# set conf to app config
		confObj.CONF_FILE = AddSep(confObj.APP_CONF_DIR) + confObj.APP_CONF_FILE
	elif conf == "dev":
		# set conf to dev environment config
		confObj.CONF_FILE = AddSep(confObj.DEV_CONF_DIR) + confObj.DEV_CONF_FILE
	elif conf == "sys":
		# set conf to system config
		confObj.CONF_FILE = AddSep(confObj.SYS_CONF_DIR) + confObj.SYS_CONF_FILE
	else:
		# user specified config
		confObj.CONF_FILE = conf
	
	r = confObj.Load()
	if r[0]:
		return confObj
	else:
		return False

